package com.qiangesoft.easyexcel.write;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.metadata.data.*;
import com.alibaba.excel.util.FileUtils;
import com.alibaba.excel.util.ListUtils;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.metadata.WriteTable;
import com.alibaba.excel.write.metadata.style.WriteCellStyle;
import com.alibaba.excel.write.metadata.style.WriteFont;
import com.qiangesoft.easyexcel.util.ResourceFileUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.FillPatternType;
import org.apache.poi.ss.usermodel.IndexedColors;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * excel写工具类
 *
 * @author qiangesoft
 * @date 2024-04-10
 */
@Slf4j
public class ExcelWrite {

    /**
     * 写数据-传递方法
     *
     * @param fileName
     * @throws IOException
     */
    public static void write(String fileName) throws IOException {
        EasyExcel.write(fileName, WriteData.class)
                .sheet("模板")
//                .head(head()) // 动态表头
                .doWrite(() -> {
                    // todo 传入真实数据
                    return data();
                });
    }

    /**
     * 写数据-传递数据
     *
     * @param fileName
     * @throws IOException
     */
    public static void write1(String fileName) throws IOException {
        EasyExcel.write(fileName, WriteData.class)
                .sheet("模板")
                .doWrite(data());
    }

    /**
     * 写数据
     *
     * @param fileName
     * @throws IOException
     */
    public static void write2(String fileName) throws IOException {
        try (ExcelWriter excelWriter = EasyExcel.write(fileName, WriteData.class).build()) {
            WriteSheet writeSheet = EasyExcel.writerSheet("模板").build();
            excelWriter.write(data(), writeSheet);
        }
    }

    /**
     * 写数据-重复写
     *
     * @param fileName
     * @throws IOException
     */
    public static void writeRepeat(String fileName) throws IOException {
        try (ExcelWriter excelWriter = EasyExcel.write(fileName, WriteData.class).build()) {
            WriteSheet writeSheet = EasyExcel.writerSheet("模板").build();
            for (int i = 0; i < 5; i++) {
                List<WriteData> data = data();
                excelWriter.write(data, writeSheet);
            }
        }
    }

    /**
     * 写数据-多个相同sheet
     *
     * @param fileName
     * @throws IOException
     */
    public static void writeSameSheet(String fileName) throws IOException {
        try (ExcelWriter excelWriter = EasyExcel.write(fileName, WriteData.class).build()) {
            for (int i = 0; i < 5; i++) {
                WriteSheet writeSheet = EasyExcel.writerSheet(i, "模板" + i).build();
                List<WriteData> data = data();
                excelWriter.write(data, writeSheet);
            }
        }
    }

    /**
     * 写数据-多个sheet
     *
     * @param fileName
     * @throws IOException
     */
    public static void writeManySheet(String fileName) throws IOException {
        try (ExcelWriter excelWriter = EasyExcel.write(fileName).build()) {
            for (int i = 0; i < 5; i++) {
                WriteSheet writeSheet = EasyExcel.writerSheet(i, "模板" + i).head(WriteData.class).build();
                List<WriteData> data = data();
                excelWriter.write(data, writeSheet);
            }
        }
    }

    /**
     * 写数据-图
     *
     * @param fileName
     * @throws IOException
     */
    public static void writeWithImage(String fileName) throws IOException {
        String imagePath = ResourceFileUtil.getClassPathByClassLoader() + "demo/img.jpg";
        try (InputStream inputStream = ResourceFileUtil.getResourceByClassPathResource("demo/img.jpg")) {
            List<ImageWriteData> list = ListUtils.newArrayList();

            ImageWriteData imageWriteData = new ImageWriteData();
            File file = new File(imagePath);
            imageWriteData.setFile(file);
            imageWriteData.setUrl(new URL("https://www.oicfx.cn/img/logo.49129107.png"));

            imageWriteData.setByteArray(FileUtils.readFileToByteArray(file));
            imageWriteData.setString(imagePath);
            imageWriteData.setInputStream(inputStream);

            WriteCellData<Void> writeCellData = new WriteCellData<>();
            writeCellData.setType(CellDataTypeEnum.STRING);
            writeCellData.setStringValue("额外的放一些文字");
            List<ImageData> imageDataList = new ArrayList<>();
            ImageData imageData = new ImageData();
            imageData.setImage(FileUtils.readFileToByteArray(file));
            imageData.setImageType(ImageData.ImageType.PICTURE_TYPE_JPEG);
            imageDataList.add(imageData);
            writeCellData.setImageDataList(imageDataList);
            imageWriteData.setWriteCellDataFile(writeCellData);
            list.add(imageWriteData);

            // 写入数据
            EasyExcel.write(fileName, ImageWriteData.class).sheet().doWrite(list);
        }
    }

    /**
     * 写数据-根据模板
     *
     * @param fileName
     * @param templateName
     * @throws IOException
     */
    public static void writeWithTemplate(String fileName, String templateName) throws IOException {
        String path = ResourceFileUtil.getClassPathByClassLoader() + templateName;
        EasyExcel.write(fileName, WriteData.class).withTemplate(path).sheet().doWrite(data());
    }

    /**
     * 写数据-单元格样式
     *
     * @param fileName
     */
    public static void writeCellData(String fileName) {
        ExcelWriteCellData excelWriteCellData = new ExcelWriteCellData();

        // 设置超链接
        WriteCellData<String> hyperlink = new WriteCellData<>("官方网站");
        excelWriteCellData.setHyperlink(hyperlink);
        HyperlinkData hyperlinkData = new HyperlinkData();
        hyperlink.setHyperlinkData(hyperlinkData);
        hyperlinkData.setAddress("https://github.com/alibaba/easyexcel");
        hyperlinkData.setHyperlinkType(HyperlinkData.HyperlinkType.URL);

        // 设置备注
        WriteCellData<String> comment = new WriteCellData<>("备注的单元格信息");
        excelWriteCellData.setCommentData(comment);
        CommentData commentData = new CommentData();
        comment.setCommentData(commentData);
        commentData.setAuthor("Jiaju Zhuang");
        commentData.setRichTextStringData(new RichTextStringData("这是一个备注"));
        // 备注的默认大小是按照单元格的大小 这里想调整到4个单元格那么大 所以向后 向下 各额外占用了一个单元格
        commentData.setRelativeLastColumnIndex(1);
        commentData.setRelativeLastRowIndex(1);

        // 设置公式
        WriteCellData<String> formula = new WriteCellData<>();
        excelWriteCellData.setFormulaData(formula);
        FormulaData formulaData = new FormulaData();
        formula.setFormulaData(formulaData);
        // 将 123456789 中的第一个数字替换成 2
        // 这里只是例子 如果真的涉及到公式 能内存算好尽量内存算好 公式能不用尽量不用
        formulaData.setFormulaValue("REPLACE(123456789,1,1,2)");

        // 设置单个单元格的样式 当然样式 很多的话 也可以用注解等方式。
        WriteCellData<String> writeCellStyle = new WriteCellData<>("单元格样式");
        writeCellStyle.setType(CellDataTypeEnum.STRING);
        excelWriteCellData.setWriteCellStyle(writeCellStyle);
        WriteCellStyle writeCellStyleData = new WriteCellStyle();
        writeCellStyle.setWriteCellStyle(writeCellStyleData);
        // 这里需要指定 FillPatternType 为FillPatternType.SOLID_FOREGROUND 不然无法显示背景颜色.
        writeCellStyleData.setFillPatternType(FillPatternType.SOLID_FOREGROUND);
        // 背景绿色
        writeCellStyleData.setFillForegroundColor(IndexedColors.GREEN.getIndex());

        // 设置单个单元格多种样式
        // 这里需要设置 inMomery=true 不然会导致无法展示单个单元格多种样式，所以慎用
        WriteCellData<String> richTest = new WriteCellData<>();
        richTest.setType(CellDataTypeEnum.RICH_TEXT_STRING);
        excelWriteCellData.setRichText(richTest);
        RichTextStringData richTextStringData = new RichTextStringData();
        richTest.setRichTextStringDataValue(richTextStringData);
        richTextStringData.setTextString("红色绿色默认");
        // 前2个字红色
        WriteFont writeFont = new WriteFont();
        writeFont.setColor(IndexedColors.RED.getIndex());
        richTextStringData.applyFont(0, 2, writeFont);
        // 接下来2个字绿色
        writeFont = new WriteFont();
        writeFont.setColor(IndexedColors.GREEN.getIndex());
        richTextStringData.applyFont(2, 4, writeFont);

        List<ExcelWriteCellData> data = new ArrayList<>();
        data.add(excelWriteCellData);
        EasyExcel.write(fileName, ExcelWriteCellData.class).inMemory(true).sheet("模板").doWrite(data);
    }

    /**
     * 写数据
     *
     * @param fileName
     */
    public static void writeTable(String fileName) {
        try (ExcelWriter excelWriter = EasyExcel.write(fileName, WriteData.class).build()) {
            // 把sheet设置为不需要头 不然会输出sheet的头 这样看起来第一个table 就有2个头了
            WriteSheet writeSheet = EasyExcel.writerSheet("模板").needHead(Boolean.FALSE).build();
            // 这里必须指定需要头，table 会继承sheet的配置，sheet配置了不需要，table 默认也是不需要
            WriteTable writeTable0 = EasyExcel.writerTable(0).needHead(Boolean.TRUE).build();
            WriteTable writeTable1 = EasyExcel.writerTable(1).needHead(Boolean.TRUE).build();
            // 第一次写入会创建头
            excelWriter.write(data(), writeSheet, writeTable0);
            // 第二次写如也会创建头，然后在第一次的后面写入数据
            excelWriter.write(data(), writeSheet, writeTable1);
        }
    }

    /**
     * 写数据-带批注
     *
     * @param fileName
     */
    public static void writeComment(String fileName) {
        EasyExcel.write(fileName, WriteData.class)
                .inMemory(Boolean.TRUE)
                .registerWriteHandler(new CommentWriteHandler())
                .sheet("模板")
                .doWrite(data());
    }

    /**
     * 构造数据
     *
     * @return
     */
    private static List<WriteData> data() {
        List<WriteData> list = ListUtils.newArrayList();
        for (int i = 0; i < 10; i++) {
            WriteData data = new WriteData();
            data.setString("字符串" + i);
            data.setDate(new Date());
            data.setDoubleData(0.56);
            list.add(data);
        }
        return list;
    }

}
